﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using QFlow.Data;
using QFlow.Core;

namespace QFlow.Windows.Forms
{
    public partial class NewSalesOrder : Utils.BaseForm
    {
        bool _New;
        SaleOrder _Order;
        int _OriginalStatus;
        bool _Change = false;

        /// <summary>
        /// Initializes a new instance of the <see cref="NewSalesOrder"/> class.
        /// </summary>
        /// <param name="dialog">if set to <c>true</c> [dialog].</param>
        /// <param name="context">The context.</param>
        public NewSalesOrder(bool dialog, QFlowDbContext context)
            : base(context)
        {
            InitializeComponent();
            _New = true;
            btnCancel.Visible = dialog;
            _Order = new SaleOrder();

            _Order.PaymentMethod = context.PaymentMethods.GetPendingMethod();
            _Order.OrderStatus = context.OrderStatus.GetPendingStatus();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="NewSalesOrder"/> class.
        /// </summary>
        /// <param name="sOrder">The s order.</param>
        /// <param name="context">The context.</param>
        public NewSalesOrder(SaleOrder sOrder, QFlowDbContext context)
            : base(context)
        {
            InitializeComponent();
            _New = false;
            btnCancel.Visible = true;
            _Order = sOrder;
            _OriginalStatus = _Order.StatusID;
            this.Text = QFlow.Windows.Properties.Resources.FRMEditSOrder;
        }

        #region [ Events ]

        /// <summary>
        /// Handles the Load event of the NewSalesOrder control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void NewSalesOrder_Load(object sender, EventArgs e)
        {
            cmbCustomer.DisplayMember = "Name";
            cmbCustomer.ValueMember = "CustomerID";
            cmbCustomer.DataSource = this.Context.Customers.ToArray();

            if (_New)
            {
                txtStatus.Text = _Order.OrderStatus.ToString();
                txtPaymentMethod.Text = _Order.PaymentMethod.ToString();
            }
            else
            {
                SetControls();
            }

            //Save the current Values
            Accounting.SaveCurrentValues();
        }

        /// <summary>
        /// Sets the controls.
        /// </summary>
        private void SetControls()
        {
            txtID.Text = _Order.SaleOrderID.ToString();
            cmbCustomer.SelectedValue = _Order.CustomerID;
            if (_Order.AccountingTransactions.Count > 0)
                cmbCustomer.Enabled = false;

            txtDiscountPercent.Text = _Order.DiscountPercent.ToString();

            gvItems.AutoGenerateColumns = false;
            gvItems.DataSource = _Order.SaleItems;

            if (_Order.StatusID != this.Context.OrderStatus.GetPendingStatus().StatusID)
            {
                cmbCustomer.Enabled = false;
                grpDiscount.Enabled = false;
                txtDiscountPercent.ReadOnly = true;
                txtDiscountValue.ReadOnly = true;
                grpItems.Enabled = false;
                grpPayments.Enabled = false;
            }
            if (_Order.StatusID == this.Context.OrderStatus.GetClosedStatus().StatusID)
            {
                btnPrint.Visible = true;
            }
        }

        /// <summary>
        /// Handles the TextChanged event of the txtDiscountValue control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void txtDiscountValue_TextChanged(object sender, EventArgs e)
        {
            if (!_Change)
            {
                _Change = true;
                double value = 0.0;
                if (double.TryParse(txtDiscountValue.Text, out value))
                {
                    double withoutDiscount = SaleOrderManager.CalculateOrderValueWithoutDiscount(_Order);
                    txtDiscountPercent.Text = SaleOrderManager.CalculateDiscountPercent(value, withoutDiscount).ToString("F");
                    txtAfterDiscount.Text = (withoutDiscount - value).ToString("F");
                }
                _Change = false;
            }
        }

        /// <summary>
        /// Handles the TextChanged event of the txtDiscountPercent control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void txtDiscountPercent_TextChanged(object sender, EventArgs e)
        {
            if (!_Change)
            {
                _Change = true;
                double percent = 0.0;
                if (double.TryParse(txtDiscountPercent.Text, out percent))
                {
                    double beforeDiscount = SaleOrderManager.CalculateOrderValueWithoutDiscount(_Order);
                    double discountValue = SaleOrderManager.CalculateDicountValue(percent, beforeDiscount);

                    txtDiscountValue.Text = discountValue.ToString("F");
                    txtAfterDiscount.Text = (beforeDiscount - discountValue).ToString("F");
                }
                _Change = false;
            }
        }

        #endregion

        #region [ Items ]

        /// <summary>
        /// Handles the Click event of the btnAdd control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnAdd_Click(object sender, EventArgs e)
        {
            NewSalesOrderItem frm = new NewSalesOrderItem(_Order, this.Context);
            frm.ShowDialog();
            RefreshForm();
        }

        /// <summary>
        /// Handles the Click event of the btnEdit control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnEdit_Click(object sender, EventArgs e)
        {
            EditItem();
        }

        private void gvItems_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            if (gvItems.Columns[e.ColumnIndex].Name != "btnReceived")
                EditItem();
        }

        private void EditItem()
        {
            if (gvItems.SelectedRows.Count != 0)
            {
                SaleItem item = gvItems.SelectedRows[0].DataBoundItem as SaleItem;
                if ((item.IsAttached() && this.Context.ItemTypes.IsPending(item.ItemTypeID)) || !item.IsAttached())
                {
                    NewSalesOrderItem frm = new NewSalesOrderItem(_Order, item, this.Context);
                    frm.ShowDialog();
                    RefreshForm();
                }
                else
                {
                    MessageBox.Show(QFlow.Windows.Properties.Resources.MBCantEditItem, QFlow.Windows.Properties.Resources.MBErrorCaption, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                }
            }
        }

        private void btnDelete_Click(object sender, EventArgs e)
        {
            if (gvItems.SelectedRows.Count != 0)
            {
                SaleItem item = gvItems.SelectedRows[0].DataBoundItem as SaleItem;
                if ((item.IsAttached() && this.Context.ItemTypes.IsPending(item.ItemTypeID)) || !item.IsAttached())
                {
                    if (MessageBox.Show(QFlow.Windows.Properties.Resources.MBDeleteItem, QFlow.Windows.Properties.Resources.MBConfirmCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                    {
                        SaleOrderManager.RemoveSaleItem(item, _Order);
                        RefreshForm();
                    }
                }
                else
                {
                    MessageBox.Show(QFlow.Windows.Properties.Resources.MBCantDeleteItem, QFlow.Windows.Properties.Resources.MBErrorCaption, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                }
            }
        }

        private void gvItems_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if (gvItems.SelectedRows.Count > 0)
            {
                if (gvItems.Columns[e.ColumnIndex].Name == "btnReceived")
                {
                    SaleItem item = gvItems.SelectedRows[0].DataBoundItem as SaleItem;
                    if (Context.ItemTypes.IsPending(item.ItemTypeID))
                    {
                        if (MessageBox.Show(QFlow.Windows.Properties.Resources.MBReceiveItem, QFlow.Windows.Properties.Resources.MBConfirmCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                        {
                            SaleOrderManager.ReceiveItem(item);
                            RefreshForm();
                        }
                    }
                }
            }
        }

        private void btnReceiveItems_Click(object sender, EventArgs e)
        {
            if (_Order.SaleItems.Count > 0)
            {
                if (MessageBox.Show(QFlow.Windows.Properties.Resources.MBReceiveItems, QFlow.Windows.Properties.Resources.MBConfirmCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                {
                    SaleOrderManager.ReceiveItems(_Order);
                    RefreshForm();
                }
            }
        }

        private void gvItems_SelectionChanged(object sender, EventArgs e)
        {
            if (gvItems.SelectedRows.Count > 0)
            {
                btnEdit.Enabled = true;
                btnDelete.Enabled = true;
            }
            else
            {
                btnEdit.Enabled = false;
                btnDelete.Enabled = false;
            }
        }

        #endregion

        #region [ Payments ]

        private void btnAddPayment_Click(object sender, EventArgs e)
        {
            NewPayment frm = new NewPayment(Context, true);
            if (frm.ShowDialog() == DialogResult.OK)
            {
                SaleOrderManager.CreatePayment(frm.Amount, frm.SelectedAccount, _Order);
                RefreshForm();
            }
        }

        private void btnEditPayment_Click(object sender, EventArgs e)
        {
            EditPayment();
        }

        private void EditPayment()
        {
            if (gvPayments.SelectedRows.Count != 0)
            {
                AccountingTransaction transaction = gvPayments.SelectedRows[0].DataBoundItem as AccountingTransaction;
                if (!transaction.IsAttached())
                {
                    NewPayment frm = new NewPayment(Context, true, transaction.Amount, transaction.Account);
                    if (frm.ShowDialog() == DialogResult.OK)
                    {
                        SaleOrderManager.UpdatePayment(transaction, frm.Amount, frm.SelectedAccount, _Order);
                        RefreshForm();
                    }
                }
                else
                {
                    MessageBox.Show(QFlow.Windows.Properties.Resources.MBCantEditPayment, QFlow.Windows.Properties.Resources.MBErrorCaption, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                }
            }
        }

        private void btnDeletePayment_Click(object sender, EventArgs e)
        {
            if (gvPayments.SelectedRows.Count != 0)
            {
                AccountingTransaction transaction = gvPayments.SelectedRows[0].DataBoundItem as AccountingTransaction;
                if (!transaction.IsAttached())
                {
                    SaleOrderManager.DeletePayment(transaction, _Order);
                    RefreshForm();
                }
                else
                {
                    MessageBox.Show(QFlow.Windows.Properties.Resources.MBCantDeletePayment, QFlow.Windows.Properties.Resources.MBErrorCaption, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                }
            }
        }

        private void gvPayments_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            EditPayment();
        }

        private void gvPayments_SelectionChanged(object sender, EventArgs e)
        {
            if (gvPayments.Rows.Count > 0)
            {
                btnEditPayment.Enabled = true;
                btnDeletePayment.Enabled = true;
            }
            else
            {
                txtDiscountPercent.ReadOnly = false;
                txtDiscountValue.ReadOnly = false;

                btnEditPayment.Enabled = false;
                btnDeletePayment.Enabled = false;
            }
        }

        private void btnPayOrder_Click(object sender, EventArgs e)
        {
            if (_Order.SaleItems.Count > 0)
            {
                double discount;
                if (double.TryParse(txtDiscountPercent.Text, out discount))
                {
                    double paidAmount = SaleOrderManager.CalculatePaidAmount(_Order);
                    if (paidAmount >= SaleOrderManager.CalculateOrderValue(_Order, discount))
                    {
                        MessageBox.Show(QFlow.Windows.Properties.Resources.MBAlreadyPaid, QFlow.Windows.Properties.Resources.MBWarningCaption, MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);
                    }
                    else if (MessageBox.Show(QFlow.Windows.Properties.Resources.MBPayOrder, QFlow.Windows.Properties.Resources.MBConfirmCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                    {
                        SaleOrderManager.PayOrder(_Order, discount);

                        txtDiscountPercent.ReadOnly = true;
                        txtDiscountValue.ReadOnly = true;

                        RefreshForm();
                    }
                }
                else MessageBox.Show(QFlow.Windows.Properties.Resources.MBDiscountNotValid, QFlow.Windows.Properties.Resources.MBErrorCaption, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
            }
        }

        private void gvPayments_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
        {
            if (_Order != null)
            {
                foreach (DataGridViewRow row in gvPayments.Rows)
                {
                    AccountingTransaction transaction = row.DataBoundItem as AccountingTransaction;
                    row.Cells[3].Value = transaction.Account1.AccountID == Context.Accounts.GetCashirAccount().AccountID
                        ? QFlow.Windows.Properties.Resources.CMBCashir : QFlow.Windows.Properties.Resources.CMBSafe;
                }
            }
        }

        #endregion

        private void NewSalesOrder_Activated(object sender, EventArgs e)
        {
            RefreshForm();
        }

        private void RefreshForm()
        {
            if (_Order.SaleItems.Count > 0)
                grpDiscount.Enabled = true;
            else grpDiscount.Enabled = false;

            double orderValue = SaleOrderManager.CalculateOrderValueWithoutDiscount(_Order);
            txtValue.Text = orderValue.ToString("F");
            //update discount value
            _Change = true;
            double percent = 0.0;
            if (double.TryParse(txtDiscountPercent.Text, out percent))
            {
                double discountValue = SaleOrderManager.CalculateDicountValue(percent, orderValue);
                double afterDiscount = orderValue - discountValue;

                txtDiscountValue.Text = discountValue.ToString("F");
                txtAfterDiscount.Text = afterDiscount.ToString("F");

                SaleOrderManager.SetOrderStatus(_Order, percent);
                txtStatus.Text = _Order.OrderStatus.Status;
                txtPaymentMethod.Text = _Order.PaymentMethod.PaymentMethod1;
            }
            _Change = false;

            gvItems.AutoGenerateColumns = false;
            gvItems.DataSource = _Order.SaleItems.ToArray();

            gvPayments.AutoGenerateColumns = false;
            gvPayments.DataSource = _Order.AccountingTransactions.ToArray();
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            if (superValidator1.Validate())
            {
                //if the order is new
                try
                {
                    if (_Order.SaleItems.Count > 0)
                    {
                        if (_New)
                        {
                            double discount = double.Parse(txtDiscountPercent.Text);
                            int checkOrder = SaleOrderManager.CheckOrderPayments(_Order, discount);
                            bool saveOrder = false;
                            if (checkOrder > 0)
                            {
                                saveOrder = MessageBox.Show(QFlow.Windows.Properties.Resources.MBSalePaidMore,
                                    QFlow.Windows.Properties.Resources.MBQuestionCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes;
                            }
                            else if (checkOrder < 0)
                            {
                                saveOrder = MessageBox.Show(QFlow.Windows.Properties.Resources.MBSalePaidLess,
                                    QFlow.Windows.Properties.Resources.MBQuestionCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes;
                            }
                            else
                            {
                                saveOrder = MessageBox.Show(QFlow.Windows.Properties.Resources.MBSaveOrder, QFlow.Windows.Properties.Resources.MBConfirmCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.Yes;
                            }
                            if (saveOrder)
                            {
                                SaleOrderManager.CreateSaleOrder(_Order, double.Parse(txtDiscountPercent.Text), cmbCustomer.SelectedItem as Customer);
                            }
                            else
                            {
                                return;
                            }
                        }
                        else
                        {
                            if (_OriginalStatus == this.Context.OrderStatus.GetPendingStatus().StatusID)
                            {
                                double discount = double.Parse(txtDiscountPercent.Text);
                                int checkOrder = SaleOrderManager.CheckOrderPayments(_Order, discount);
                                bool saveOrder = false;
                                if (checkOrder > 0)
                                {
                                    saveOrder = MessageBox.Show(QFlow.Windows.Properties.Resources.MBSalePaidMore,
                                        QFlow.Windows.Properties.Resources.MBQuestionCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes;
                                }
                                else if (checkOrder < 0)
                                {
                                    saveOrder = MessageBox.Show(QFlow.Windows.Properties.Resources.MBSalePaidLess,
                                        QFlow.Windows.Properties.Resources.MBQuestionCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes;
                                }
                                else
                                {
                                    saveOrder = MessageBox.Show(QFlow.Windows.Properties.Resources.MBSaveOrder, QFlow.Windows.Properties.Resources.MBConfirmCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.Yes;
                                }
                                if (saveOrder)
                                {
                                    SaleOrderManager.UpdateSaleOrder(_Order, double.Parse(txtDiscountPercent.Text), cmbCustomer.SelectedItem as Customer);
                                }
                                else
                                {
                                    return;
                                }
                            }
                            else
                            {
                                return;
                            }
                        }
                        PostSave();
                    }
                }
                catch
                {
                    MessageBox.Show(QFlow.Windows.Properties.Resources.MBCantSaveChanges, QFlow.Windows.Properties.Resources.MBErrorCaption, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                }
            }
        }

        private void PostSave()
        {
            if (_Order.OrderStatus.StatusID == this.Context.OrderStatus.GetClosedStatus().StatusID)
            {
                if (MessageBox.Show(QFlow.Windows.Properties.Resources.MBPrintOrder, QFlow.Windows.Properties.Resources.MBQuestionCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
                    btnPrint.PerformClick();
            }
            Accounting.CommitCurentValues();
            this.Close();
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void NewSalesOrder_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!_New)
            {
                //discard new items of this order
                for (int i = _Order.AccountingTransactions.Count - 1; i >= 0; i--)
                {
                    var item = _Order.AccountingTransactions[i];
                    if (!item.IsAttached())
                        _Order.AccountingTransactions.Remove(item);
                }
                for (int i = _Order.SaleItems.Count - 1; i >= 0; i--)
                {
                    var item = _Order.SaleItems[i];
                    if (!item.IsAttached())
                        _Order.SaleItems.Remove(item);
                }
            }

            Accounting.RestorValues();
            this.Context.DiscardChanges();
        }

        private void btnPrint_Click(object sender, EventArgs e)
        {
            List<QFlow.Windows.Forms.PrintOrder.PrintItem> items = new List<PrintOrder.PrintItem>();
            foreach (var item in _Order.SaleItems)
            {
                if (!Context.ItemTypes.IsReturned(item.ItemTypeID))
                {
                    QFlow.Windows.Forms.PrintOrder.PrintItem printItem = new PrintOrder.PrintItem()
                    {
                        ItemPrice = item.UnitPrice,
                        Name = item.StockableProduct.Product.Name,
                        Quantity = item.Quantity
                    };
                    items.Add(printItem);
                }
            }

            PrintOrder order = new PrintOrder()
            {
                Date = _Order.Date,
                OrderID = _Order.SaleOrderID.ToString(),
                Title = "طلبية بيع",
                Value = SaleOrderManager.CalculateOrderValue(_Order, _Order.DiscountPercent),
                Items = items
            };

            OrderPrinter printer = new OrderPrinter();
            printer.PrintOrder(order);
        }

        string _globalBarcode = "";
        private void gvItems_KeyDown(object sender, KeyEventArgs e)
        {
            if ((e.KeyData & Keys.Enter) != Keys.Enter)
                _globalBarcode += (char)e.KeyValue;
            else
            {
                try
                {
                    _globalBarcode = _globalBarcode.Remove(0, 1);
                    AddNewItem(_globalBarcode);
                    _globalBarcode = string.Empty;
                }
                catch
                {
                    _globalBarcode = string.Empty;
                }
            }
        }

        /// <summary>
        /// Adds the new item.
        /// </summary>
        /// <param name="barcode">The barcode.</param>
        private void AddNewItem(string barcode)
        {
            if (_Order.StatusID != this.Context.OrderStatus.GetCanceledStatus().StatusID
                &&
                _Order.StatusID != this.Context.OrderStatus.GetAdjustedStatus().StatusID)
            {
                StockableProduct product = this.Context.StockableProducts.SingleOrDefault(p => p.GlobalBarcode == barcode);
                if (product == null)
                {
                    MessageBox.Show(QFlow.Windows.Properties.Resources.MBInvalidBarcode, QFlow.Windows.Properties.Resources.MBErrorCaption, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                }
                else
                {
                    List<PurchaseItem> availableItems;
                    List<double> availableQuantites;
                    SaleOrderManager.GetAvailableItems(product.ProductID, out availableItems, out availableQuantites);
                    if (availableItems.Count != 0)
                    {
                        SaleItem item = null;
                        int itemIndex = -1;
                        //check if product exist
                        for (int i = 0; i < _Order.SaleItems.Count; i++)
                        {
                            if (Context.ItemTypes.IsPending(_Order.SaleItems[i].ItemTypeID))
                            {
                                if (_Order.SaleItems[i].ProductID == product.ProductID)
                                {
                                    itemIndex = i;
                                    break;
                                }
                            }
                        }
                        if (itemIndex == -1)
                        {
                            if (!SaleOrderManager.CheckProductStatus(product, 1, availableQuantites[0], _Order))
                                return;
                            SaleOrderManager.CreateSaleItem(1, product.SalesUnitPrice,
                            product, SaleOrderManager.CaluclateItemDiscount(product.SalesUnitPrice, product.SalesUnitPrice), SaleOrderManager.CalculateProfitPercent(product.PurchaseUnitPrice, product.SalesUnitPrice), 0,
                            "", availableItems[0], _Order);
                        }
                        else
                        {
                            item = _Order.SaleItems[itemIndex];
                            if (!SaleOrderManager.CheckProductStatus(product, 1, availableQuantites[0], _Order))
                                return;
                            SaleOrderManager.UpdateSaleItem(item, item.Quantity + 1, item.UnitPrice, product, item.DiscountPercent, item.ProfitPercent, 0, "", availableItems[0]);
                        }
                        RefreshForm();
                    }
                    else
                    {
                        MessageBox.Show(QFlow.Windows.Properties.Resources.MBProductShortage, QFlow.Windows.Properties.Resources.MBErrorCaption, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                    }
                }
            }
        }
    }
}
